using System;
using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting;
using Sedna.API.Remoting;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Config;


namespace Sedna.API.Remoting
{
    /// <summary>
    /// Factory for generating client SAO proxies, which are used to wrap transparent proxies. 
    /// </summary>
    public class SaoProxyFactory
    {

        private static AssemblyBuilder assembly;

        static SaoProxyFactory()
        {
            AssemblyName an = new AssemblyName();
            an.Name = "Spring.RemoteObjects.Client";
            assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        }

        private static object BuildSaoProxy(Type serviceInterface, string serviceUri)
        {
            object target = Activator.GetObject(serviceInterface, serviceUri);
            SaoClientProxyTypeBuilder builder = new SaoClientProxyTypeBuilder();
            builder.TargetType = target.GetType();
            builder.Name = serviceInterface.Name + "Proxy";
            builder.Interfaces = new Type[] { serviceInterface };
            builder.BaseType = typeof(object);
            Type proxyType = builder.BuildProxyType();
            ConstructorInfo constructor = proxyType.GetConstructor(new Type[0]);
            object proxy = constructor.Invoke(new object[0]);
            SaoClientProxyTypeBuilder.SetTarget(proxy, target);
            return proxy;
        }

        
        /// <summary>
        /// Return the SAO proxy
        /// </summary>
        /// <returns>the SAO proxy</returns>
        public static object GetObject(Type serviceInterface, string serviceUri)
        {
            if (serviceUri == null)
            {
                throw new ArgumentException("The ServiceUri property is required.");
            }

            if (serviceInterface == null)
            {
                throw new ArgumentException("The ServiceInterface property is required.");
            }

            if (!serviceInterface.IsInterface)
            {
                throw new ArgumentException("ServiceInterface must be an interface");
            }

            return BuildSaoProxy(serviceInterface, serviceUri);
        }

    }
}
